<?php
class N_Model_Abstract
{
	/**
	 * 表名,无前缀
	 *
	 * @var string
	 */
	protected $_tableName;
	
	/**
	 * 表前缀
	 *
	 * @var string
	 */
	protected $_tablePrefix;
	
	/**
	 * 主键
	 *
	 * @var string
	 */
	protected $_pk;
	
	/**
	 * 最后执行的Sql语句
	 *
	 * @var string
	 */
	protected $_lastSql;
	
	/**
	 * 是否Debug模式运行
	 *
	 * @var bool
	 */
	private $_debug = false;
	
	public function __construct()
	{
		
	}
	
	/**
	 * 设置表名称(不包括前缀部分)和表名前缀
	 *
	 * @param string $tableName
	 * @param string $tablePrefix
	 */
	public function setTable($tableName, $tablePrefix = '')
	{
		if (empty($tableName))
		{
			throw new Exception("数据库表不能为空!");
		}
		$this->_tableName = $tableName;
		$this->_tablePrefix = $tablePrefix;
	}
	
	/**
	 * 返回由表名前缀和表名组成完整表名
	 *
	 * @return string
	 */
	public function getFullTable()
	{
		return $this->_tablePrefix.$this->_tableName;
	}
	
	/**
	 * 设置主键
	 *
	 * @param string $pk
	 */
	public function setPk($pk)
	{
		if (empty($pk))
		{
			throw new Exception("主键不能为空!");
		}
		$this->_pk = $pk;
	}
	
	public function setFetchMode(string $mode = null)
	{
		
	}
	
	/**
	 * 返回一个数据库查询语句构造对象
	 *
	 * @return DB_Select Object
	 */
	public function sel()
	{
		return N::getSingleton('DB_SELECTOR');
	}
	
	/**
	 * 根据指定字段名的指定值查找数据库记录,字段名默认为主键名
	 *
	 * @param mixed $value
	 * @param string $fieldName
	 * @return array
	 */
	public function & find($value = null, $fieldName = null, $where = null, $orderBy = null, $nums = 1)
	{
		if ($fieldName == null || $fieldName == '')
		{
			$fieldName = $this->_pk;
		}
		$sql = null;
		//Todo:过滤$fieldName
		if ($value != null || $value != '') 
		{
			$sql = "select * from ".escapeTable($this->getFullTable()).' where '.escapeField($fieldName).' = '.escapeValue($value);
		}
		else 
		{
			$sql = "select * from ".escapeTable($this->getFullTable());
		}
		//Todo:过滤$orderBy
		if ($where != null || $where != '')
		{
			$sql .= ' where '.$where;
		}
		//Todo:过滤$orderBy
		if ($orderBy != null || $orderBy != '')
		{
			$sql .= ' order by '.$orderBy;
		}
		
		$nums = (int)$nums;
		if ($nums > 1)
		{
			$sql .= ' limit 0, '.$nums;
		}
		
		$ps = $this->query($sql);
		$rs = $ps->fetchAll();
		return $rs;
	}
	
	/**
	 * 同find方法
	 *
	 * @param mixed $value
	 * @param string $fieldName
	 * @return array
	 */
	public function & get($value = null, string $fieldName = null)
	{
		return $this->find($value, $fieldName);
	}
	
	public function findAll(string $orderBy = null)
	{
		return $this->find(null, null, $orderBy);
	}
	
	/**
	 * 根据字段名返回一条数据库记录
	 *
	 * @param string $value
	 * @param string $orderBy
	 * @param string $fieldName
	 * @return resource
	 */
	public function & getOne($value, $orderBy = '', $fieldName = '')
	{
		if ($fieldName == '')
		{
			$fieldName = $this->_pk;
		}
		$sql = null;
		if ($value != '')
		{
			if ($orderBy == '') 
			{
				$sql = "select * from ".escapeTable($this->getFullTable()).' where '.escapeField($fieldName).' = '.escapeValue($value).' limit 1';
			}
			else 
			{
				$sql = "select * from ".escapeTable($this->getFullTable())
					.' where '.escapeField($fieldName).' = '.escapeValue($value)
					.' order by '.escapeField($orderBy).' limit 1';
			}
		}
		else 
		{
			if ($orderBy == '') 
			{
				$sql = "select * from ".escapeTable($this->getFullTable()).' limit 1';
			}
			else 
			{
				$sql = "select * from ".escapeTable($this->getFullTable())
					.' order by '.escapeField($orderBy).' limit 1';
			}
		}
		$ps = $this->query($sql);
		$rs = $ps->fetchAll();
		return $rs;
	}
	
	/**
	 * 插入数据库记录
	 * 
	 * 形式1=> array($fieldname1=>$value1, $fieldname2=>$value2, ...)
	 * 形式2=> array(array($fieldname1, $fieldname2, ...), array($value1, $value2, ...));
	 * 形式3=> array($value1, value2, ...)
	 * 形式4 => $fieldname, $value
	 *
	 */
	public function insert()
	{
		$param = func_get_args();
		$size = sizeof($param);
		$sql = null;
		if ($size == 1)
		{
			if ($this->_arrayHasColumnName($param[0]))
			{
				$field = array();
				$value = array();
				//如果主键没有指定
				if (!array_key_exists($this->_pk, $param[0]))
				{
					array_push($field, $this->_pk);
					array_push($value, 'NULL');
				}
				foreach ($param[0] as $key=>$v)
				{
					array_push($field, $key);
					array_push($value, $v);
				}
				$sql = 'insert into '.escapeTable($this->getFullTable())
						.'('.escapeField($field).') values ('.escapeValue($value).')';
			}
			else 
			//此时请注意:数组中的数据排序一定要和数据库中字段顺序相同
			{
				$value = array();
				if (in_array('NULL', $param[0]))
				{
					array_push($value, 'NULL');
				}
				foreach ($param[0] as $key=>$v)
				{
					array_push($value, $v);
				}
				$sql = 'insert into '.escapeTable($this->getFullTable())
						.' values ('.escapeValue($value).')';
			}
		}
		else if ($size == 2)
		{
			$field = $param[0];
			$value = $param[1];
			$sql = 'insert into '.escapeTable($this->getFullTable())
					.' ('.escapeField($field).')'
					.' values ('.escapeValue($value).')';
		}
		
		return $this->query($sql);
	}
	
	public function save()
	{
		$param = func_get_args();
		return call_user_func_array(array($this, 'insert'), $param);
	}
	
	/**
	 * 删除数据库记录
	 *
	 * @param mixed $value
	 * @param string $fieldName
	 * @param string $whereCondition
	 */
	public function delete($value, $fieldName = '', $whereCondition = '')
	{
		$sql = null;
		if ($fieldName == '')
		{
			$fieldName = $this->_pk;
		}
		if ($whereCondition == '')
		{
			$sql = 'delete from '.escapeTable($this->getFullTable())
					.'where '.escapeField($fieldName).' = '.escapeValue($value);
		}
		return $this->query($sql);
	}
	
	public function remove($value, $fieldName = '', $whereCondition = '')
	{
		return $this->delete($value, $fieldName, $whereCondition);
	}
	
	/**
	 * 判断一个数组是否为联合索引数组(使用字符串作为索引)
	 * 该函数只适用于本类中
	 *
	 * @param array $array
	 * @return bool
	 */
	private function _arrayHasColumnName($array)
	{
		foreach ($array as $key=>$value)
		{
			if (is_string($key) && !is_int($key))
			{
				return true;
			}
			else 
			{
				return false;
			}
		}
	}
	
	/**
	 * 调试模式,可以打印执行的sql语句
	 *
	 * @param bool $debug
	 */
	public function setDebug($debug = true)
	{
		$this->_debug = $debug;
	}
	
	public function query($sql)
	{
		$this->_lastSql = $sql;
		if ($this->_debug)
		{
			print "执行sql语句:".$sql;
		}
		$db = $this->getDb();
		$rs = $db->query($sql);
		return $rs;
	}
	
	public function getDb()
	{
		$dbClass = N::getIni('DB_CLASS');
		$factory = N::getSingleton($dbClass);
		return $factory->factory();
	}
	
	/**
	 * 返回最后一次数据库错误信息
	 *
	 * @return string
	 */
	public function getError()
	{
		$db = $this->getDb();
		return $db->errorInfo[1];
	}
	
	/**
	 * 返回最后一次执行的sql语句
	 *
	 * @return string
	 */
	public function getLastSql()
	{
		return $this->_lastSql;
	}
}